#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QLabel>

#ifdef __GNUC__
    #include <cpuid.h>
#elif defined(_MSC_VER)
    #if _MSC_VER >= 1400
        #include <intrin.h>
    #endif
#else
    #error Only supports MSVC or GCC
#endif

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    QLabel *pLabel = new QLabel(this);
    pLabel->setText(QStringLiteral("地址："));
    ui->mainToolBar->addWidget(pLabel);
    m_pAddressString = new QLineEdit(this);
    connect(m_pAddressString, SIGNAL(returnPressed()), this, SLOT(on_pbtnSearch_clicked()));
    ui->mainToolBar->addWidget(m_pAddressString);

    m_pSearch = new QPushButton(this);
    m_pSearch->setObjectName("pbtnSearch");
    m_pSearch->setText("...");
    ui->mainToolBar->addWidget(m_pSearch);
    connect(m_pSearch, SIGNAL(clicked()), this, SLOT(on_pbtnSearch_clicked()));

    m_pReflush = new QPushButton(this);
    m_pReflush->setObjectName("pbtnReflush");
    m_pReflush->setText(QStringLiteral("刷新"));
    ui->mainToolBar->addWidget(m_pReflush);
    connect(m_pReflush, SIGNAL(clicked()), this, SLOT(on_pbtnReflush_clicked()));

    this->setCentralWidget(&m_view);
    QString htmlFilePath = qApp->applicationDirPath() + "/WebGetSystemEnv.html";
    if (!htmlFilePath.startsWith("file://"))
    {
        htmlFilePath.insert(0, "file://");
    }
    m_view.load(QUrl(htmlFilePath));
    m_pAddressString->setText(htmlFilePath);

    m_jsContext = new JsContext(this);
    m_webChannel = new QWebChannel(this);
    m_webChannel->registerObject("context", m_jsContext);
    m_view.page()->setWebChannel(m_webChannel);
    connect(m_jsContext, &JsContext::recvdMsg, this, [this](const int& msg) {
        if (0 == msg){
            QString str = get_cpuId();
            m_jsContext->sendMsg(m_view.page(), str);
        }
        else if (1 == msg){
            QStringList listMac = get_mac();
            for(QString str : listMac){
                m_jsContext->sendMsg(m_view.page(), str);
            }
        }
        ui->statusBar->showMessage(QString("Received message: %1").arg(msg), 3000);
    });

    init();
}

MainWindow::~MainWindow()
{
    delete ui;
}

QStringList MainWindow::get_mac()
{
    QStringList mac_list;
    QString strMac;
    QList<QNetworkInterface> ifaces = QNetworkInterface::allInterfaces();
    for (int i=0; i<ifaces.count(); i++)
    {
        QNetworkInterface iface = ifaces.at(i);
        //过滤掉本地回环地址、没有开启的地址
        if (iface.flags().testFlag(QNetworkInterface::IsUp) && !iface.flags().testFlag(QNetworkInterface::IsLoopBack))
        {
            //过滤掉虚拟地址
            if (!(iface.humanReadableName().contains("VMware",Qt::CaseInsensitive)))
            {
                strMac = iface.hardwareAddress();
                mac_list.append(strMac);
            }
        }
    }
    return mac_list;
}

void MainWindow::getcpuid(unsigned int CPUInfo[], unsigned int InfoType)
{
#if defined(__GNUC__)// GCC
    __cpuid(InfoType, CPUInfo[0], CPUInfo[1], CPUInfo[2], CPUInfo[3]);
#elif defined(_MSC_VER)// MSVC
#if _MSC_VER >= 1400 //VC2005才支持__cpuid
    __cpuid((int*)(void*)CPUInfo, (int)(InfoType));
#else //其他使用getcpuidex
    getcpuidex(CPUInfo, InfoType, 0);
#endif
#endif
}

void MainWindow::getcpuidex(unsigned int CPUInfo[], unsigned int InfoType, unsigned int ECXValue)
{
#if defined(_MSC_VER) // MSVC
#if defined(_WIN64) // 64位下不支持内联汇编. 1600: VS2010, 据说VC2008 SP1之后才支持__cpuidex.
    __cpuidex((int*)(void*)CPUInfo, (int)InfoType, (int)ECXValue);
#else
    if (NULL==CPUInfo)  return;
    _asm{
        // load. 读取参数到寄存器.
        mov edi, CPUInfo;
        mov eax, InfoType;
        mov ecx, ECXValue;
        // CPUID
        cpuid;
        // save. 将寄存器保存到CPUInfo
        mov [edi], eax;
        mov [edi+4], ebx;
        mov [edi+8], ecx;
        mov [edi+12], edx;
    }
#endif
#endif
}

QString MainWindow::get_cpuId()
{
    QString cpu_id = "";
    unsigned int dwBuf[4]={0};
    unsigned long long ret = 0;
    getcpuid(dwBuf, 1);
    ret = dwBuf[3];
    ret = ret << 32;

    QString str0 = QString::number(dwBuf[3], 16).toUpper();
    QString str0_1 = str0.rightJustified(8,'0');//这一句的意思是前面补0，但是我遇到的情况是这里都填满了
    QString str1 = QString::number(dwBuf[0], 16).toUpper();
    QString str1_1 = str1.rightJustified(8,'0');//这里必须在前面补0，否则不会填满数据
    //cpu_id = cpu_id + QString::number(dwBuf[0], 16).toUpper();
    cpu_id = str0_1 + str1_1;
    return cpu_id;
}

void MainWindow::init()
{
    //测试cpu_id
    QString cpu_id = "";
    cpu_id = get_cpuId();
    qDebug() << cpu_id;
    //测试mac
    QStringList mac_list;
    mac_list = get_mac();
    for (int i=0; i<mac_list.size(); i++)
    {
        qDebug() << mac_list.at(i);
    }
}

void MainWindow::on_pbtnReflush_clicked()
{
    m_view.reload();
}

void MainWindow::on_pbtnSearch_clicked()
{
    QString str = m_pAddressString->text();
    if (!str.isEmpty()){
        if (!str.startsWith("file://", Qt::CaseInsensitive)){
            if (!str.startsWith("http://", Qt::CaseInsensitive)){
                str.insert(0, "http://");
            }
        }
        m_view.load(str);
    }
}
